package com.cloud.tmc.zxinglib.qrcode

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.Matrix
import android.util.Log
import android.widget.ImageView
import com.andy.qrcode.qrcode.DecodeFormatManager
import com.google.zxing.*
import com.google.zxing.common.BitMatrix
import com.google.zxing.common.GlobalHistogramBinarizer
import com.google.zxing.common.HybridBinarizer
import com.google.zxing.qrcode.QRCodeWriter
import java.util.*
import kotlin.math.max
import kotlin.math.min

object QrCodeUtil {
    /**
     * 创建QRCode
     *
     * @param url
     */
    fun createQRImage(qrCodeIV: ImageView, url: String?): Bitmap? {
        return createQRImage(qrCodeIV.width, qrCodeIV.height, url)
    }

    /**
     * 创建QRCode
     *
     * @param url
     */
    fun createQRImage(width: Int, height: Int, url: String?, logoBm: Bitmap? = null): Bitmap? {
        var bitmap: Bitmap? = null
        try {
            if (url == null || "" == url || url.isEmpty()) {
                return bitmap
            }
            if (!(width > 0 && height > 0)) {
                return bitmap
            }
            val hints = Hashtable<EncodeHintType, Any?>()
            hints[EncodeHintType.CHARACTER_SET] = "utf-8"
            hints[EncodeHintType.MARGIN] = 0
            //图像数据转换，使用了矩阵转换
            val bitMatrix: BitMatrix = QRCodeWriter().encode(url, BarcodeFormat.QR_CODE, width, height, hints)
            val pixels = IntArray(width * height)
            //下面这里按照二维码的算法，逐个生成二维码的图片，
            //两个for循环是图片横列扫描的结果
            for (y in 0 until height) {
                for (x in 0 until width) {
                    if (bitMatrix[x, y]) {
                        pixels[y * width + x] = -0x1000000
                    } else {
                        pixels[y * width + x] = -0x1
                    }
                }
            }
            //生成二维码图片的格式，使用ARGB_8888
            bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
            bitmap.setPixels(pixels, 0, width, 0, 0, width, height)
            if (logoBm != null) {
                bitmap = addLogo(bitmap, logoBm)
            }
            return bitmap
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return bitmap
    }

    /**
     * 在二维码中间添加Logo图案
     */
    private fun addLogo(src: Bitmap?, logo: Bitmap?): Bitmap? {
        if (src == null) {
            return null
        }
        if (logo == null) {
            return src
        }
        //获取图片的宽高
        val srcWidth = src.width
        val srcHeight = src.height
        val logoWidth = logo.width
        val logoHeight = logo.height
        if (srcWidth == 0 || srcHeight == 0) {
            return null
        }
        if (logoWidth == 0 || logoHeight == 0) {
            return src
        }
        //logo大小为二维码整体大小的1/5
        val scaleFactor = srcWidth * 1.0f / 5 / logoWidth
        var bitmap = Bitmap.createBitmap(srcWidth, srcHeight, Bitmap.Config.ARGB_8888)
        try {
            val canvas = Canvas(bitmap!!)
            canvas.drawBitmap(src, 0f, 0f, null)
            canvas.scale(
                scaleFactor,
                scaleFactor,
                (srcWidth / 2).toFloat(),
                (srcHeight / 2).toFloat()
            )
            canvas.drawBitmap(
                logo,
                ((srcWidth - logoWidth) / 2).toFloat(),
                ((srcHeight - logoHeight) / 2).toFloat(),
                null
            )
            canvas.save()
            canvas.restore()
        } catch (e: Exception) {
            bitmap = null
            e.stackTrace
        }
        return bitmap
    }

    /**
     * 解析二维码图片
     */
    fun parseCodeResult(bitmapPath: String, dimen: Int): String? {
        val bmp = compressBitmap(bitmapPath, dimen)
        val result = parseCodeResult(bmp)
        bmp.recycle()
        return result?.text
    }

    const val TAG = "[CodeUtils]"
    private fun parseCodeResult(bitmap: Bitmap): Result? {
        return parseCodeResult(getRGBLuminanceSource(bitmap))
    }

    /**
     * 二维码图片
     */
    private fun parseCodeResult(source: LuminanceSource?): Result? {
        var result: Result? = null
        val reader = MultiFormatReader()
        try {
            reader.setHints(DecodeFormatManager.QR_CODE_HINTS)
            if (source != null) {
                result = decodeInternal(reader, source)
                if (result == null) {
                    result = decodeInternal(reader, source.invert())
                }
                if (result == null && source.isRotateSupported) {
                    result = decodeInternal(reader, source.rotateCounterClockwise())
                }
            }
        } catch (e: java.lang.Exception) {
            Log.w(TAG, e.message ?: "")
        } finally {
            reader.reset()
        }
        return result
    }

    private fun decodeInternal(reader: MultiFormatReader, source: LuminanceSource): Result? {
        var result: Result? = null
        try {
            //采用HybridBinarizer解析
            result = reader.decodeWithState(BinaryBitmap(HybridBinarizer(source)))
        } catch (e: java.lang.Exception) {
            Log.w(TAG, e.message!!)
        }
        try {
            if (result == null) {
                //如果没有解析成功，再采用GlobalHistogramBinarizer解析一次
                result = reader.decodeWithState(BinaryBitmap(GlobalHistogramBinarizer(source)))
            }
        } catch (e: java.lang.Exception) {
            Log.w(TAG, e.message!!)
        }
        return result
    }

    /**
     * 压缩图片
     */
    private fun compressBitmap(path: String, dimen: Int): Bitmap {
        val newOpts = BitmapFactory.Options()
        // 开始读入图片，此时把options.inJustDecodeBounds 设回true了
        newOpts.inJustDecodeBounds = true //获取原始图片大小
        BitmapFactory.decodeFile(path, newOpts) // 此时返回bm为空
        val width = newOpts.outWidth
        val height = newOpts.outHeight
        if (width < dimen || height < dimen) {
            val scale = dimen / (min(width, height) * 1.0f)
            val matrix = Matrix()
            matrix.postScale(scale, scale, 0f, 0f)
            newOpts.inJustDecodeBounds = false
            val bm = BitmapFactory.decodeFile(path, newOpts)
            return Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true)
        } else {
            val wSize = (width / dimen)
            val hSize = (height / dimen)

            var size = max(wSize, hSize)
            if (size <= 0) size = 1
            if (size > 1) {
                newOpts.inSampleSize = size // 设置缩放比例
                // 重新读入图片，注意此时已经把options.inJustDecodeBounds 设回false了
                newOpts.inJustDecodeBounds = false
                return BitmapFactory.decodeFile(path, newOpts)
            }
        }

        return BitmapFactory.decodeFile(path)
    }


    /**
     * 获取RGBLuminanceSource
     */
    private fun getRGBLuminanceSource(bitmap: Bitmap): RGBLuminanceSource? {
        val width = bitmap.width
        val height = bitmap.height
        val pixels = IntArray(width * height)
        bitmap.getPixels(pixels, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height)
        return RGBLuminanceSource(width, height, pixels)
    }
}